# 软件主框架

import wx
import os
import pickle
import copy
import lzma

from GUIBudgetDataHandler import FrontDataHandler
from DiaCreatePro import DiaCreatePro
from DiaCreateBook import DiaCreateBook
from SqlDict import SqlDict
from DataTool import DataTool
from DiaMainChangeBook import DiaMainChangeBook
from DiaChangeBookName import DiaChangeBookName
from DiaPickTemp import DiaPickTemp
from ParseXls import ParseXls
from ParseDocx import ParseDocx
from DiaChoiceStanderd import DiaChoiceStanderd
from DiaDonate import DiaDonate


BASE_DIR = os.path.dirname(os.path.abspath(__file__))

# 需要先新建分册装饰器
def NeedBook(func):
    def wrapper(self, *args, **kwargs):
        Win = self.GetActiveChild()
        if Win is not None:
            ret = func(self, *args, **kwargs)
            return ret
        else:
            wx.MessageBox('请先新建分册!'
                , '警告!',style=wx.OK|wx.ICON_WARNING)
    return wrapper

# 需要先新建工程装饰器
def NeedPro(func):
    def wrapper(self, *args, **kwargs):
        if hasattr(self, 'ProData') and self.ProData != 5101:
            ret = func(self, *args, **kwargs)
            return ret
        else:
            wx.MessageBox('请先新建工程!'
                , '警告!',style=wx.OK|wx.ICON_WARNING)
    return wrapper


class MenuData:
    # 专门管理主框架menu的类
    def __init__(self, Instance):
        self.menuData = [
                            ['文件(&F)',
                                [
                                    ['新建工程(&N)...', '新建工程项目', Instance.OnNewPro],
                                    ['新建分册(&B)...', '新建工程分册', Instance.OnNewBook],
                                    ['', '', ''],
                                    ['打开工程(&O)...', '打开工程源文件', Instance.OnOpenPro],
                                    ['打开最近工程(&R)', 
                                        [
                                            ['', '', ''],
                                            ['清除历史记录(&C)', '清除最近打开的历史记录', Instance.OnClearHis],
                                        ]
                                    ],
                                    ['', '', ''],
                                    ['修改工程信息(&X)...', '修改工程信息', Instance.OnChangePro],
                                    ['修改分册名称(&F)...', '修改分册信息', Instance.OnChangeBook],
                                    ['设置分册(&P)...', '删除、打开或设置分册', Instance.OnSetBook],
                                    ['', '', ''],
                                    ['转换为国标预算', '转换为国标预算', Instance.OnConver2Stand],
                                    ['', '', ''],
                                    ['导入模板(&I)', '导入模板中的费率等', Instance.OnImportTemp],
                                    ['导出为(&E)...', '需要选择自定义模板', Instance.OnExportAs],
                                    ['', '', ''],
                                    ['保存(&S)', '保存工程', Instance.OnSave],
                                    ['另存为(&A)...', '另存为其他文件', Instance.OnSaveAs],
                                    ['', '', ''],
                                    ['首选项(&S)', '软件设置中心', Instance.OnSet],
                                ],
                            ],
                            ['编辑(&E)',
                                [
                                    ['撤销(&U)', '撤销上一步操作', Instance.OnUndo],
                                    ['恢复(&R)', '恢复撤销的操作', Instance.OnRestore],
                                    ['', '', ''],
                                    ['复制(&C)', '复制选中的表格', Instance.OnCopy],
                                    ['粘贴(&P)', '将粘贴板中的数据粘贴进表格', Instance.OnPaste],
                                    ['', '', ''],
                                    ['查找(&F)', '查找表格中的数据', Instance.OnFind],
                                    ['替换(&R)', '替换表格中的数据', Instance.OnReplace],
                                ]
                            ],
                            ['选项(&O)',
                                [
                                    ['文字(&F)', '调整主窗口文字', Instance.OnFont],
                                    ['表格(&G)', '调整表格', Instance.OnGrid],
                                    ['', '', ''],
                                    ['主题(&T)', '设置导入导出自定义主题', Instance.OnTheme],
                                ]
                            ],
                            ['工具(&T)',
                                [
                                    ['监视窗(&S)', '监视窗工具', Instance.OnSpy],
                                    ['定额库(&Q)', '国标定额查询及维护', Instance.OnQuota],
                                ]
                            ],
                            ['帮助(&H)',
                                [
                                    ['帮助文档(&H)', '软件帮助文档', Instance.OnHelp],
                                    ['', '', ''],
                                    ['捐助(&D)', '老板大气', Instance.OnDonate],
                                    ['关于(&A)', '关于宇宙生命以及一切', Instance.OnAbout],
                                ]
                            ],
                        ]
    
    def GetMenuData(self):
        return self.menuData

class MainFrame(wx.MDIParentFrame):

    wildcard = 'Dls files (*.dls)|*.dls|All files(*.*)|*.*'
    def __init__(self, title):
        super().__init__(None, -1, title)
        menudata = MenuData(self)
        self.filename = ''
        self.menuData = menudata.GetMenuData()

        IconPath = os.path.join(BASE_DIR, 'image/ICON/Logo32.png')
        LogoBitmap = wx.Bitmap(IconPath)
        LogoIcon = wx.Icon(LogoBitmap)
        LogoIcons = wx.IconBundle(LogoIcon)
        self.SetIcons(LogoIcons)
        
        self.createMenuBar()

        self.StatusBar = self.CreateStatusBar()

    def createMenuBar(self):
        menuBar = wx.MenuBar()
        for eachMenuData in self.menuData:
            menuLabel = eachMenuData[0]
            menuItems = eachMenuData[1]
            menuBar.Append(self.createMenu(menuItems), menuLabel)
        self.SetMenuBar(menuBar)

    def createMenu(self, menuData):
        menu = wx.Menu()
        for eachItem in menuData:
            if len(eachItem) == 2:
                label = eachItem[0]
                subMenu = self.createMenu(eachItem[1])
                menu.Append(-1, label, subMenu)

            else:
                self.createMenuItem(menu, *eachItem)

        return menu

    def createMenuItem(self, menu, label, status, handler,
        kind=wx.ITEM_NORMAL):
        if not label:
            menu.AppendSeparator()
            return
        menuItem = menu.Append(-1, label, status, kind)
        self.Bind(wx.EVT_MENU, handler, menuItem)

    # 绑定函数 文件
    def OnNewPro(self, event):
        if hasattr(self, 'ProData') and self.ProData != 5101:
            MainFrame('*').Show()
        else:
            path = os.path.join(BASE_DIR, 'db')
            Dia = DiaCreatePro(self, '新建工程', path=path)
            self.ProData = Dia.ShowModal()
            Dia.Destroy()
            if self.ProData != 5101:
                self.SetTitle(self.ProData['项目名称'])
                self.BookList = []

    @NeedPro
    def OnNewBook(self, event):
        path = os.path.join(BASE_DIR, 'db')
        Names = self.GetOtherBookNames('')
        Dia = DiaCreateBook(self, '新建分册', path=path, data=self.ProData, names=Names)
        BookData = Dia.ShowModal()
        Dia.Destroy()
        if BookData != 5101:
            index = len(self.BookList)
            self.BookList.append([index, BookData, '', 'DISPLAY'])
            ret = self.BookData2Dict(BookData)
            win = FrontDataHandler(self, ret[0], path=os.path.join(BASE_DIR, 'db'),
                **ret[1], windowname=BookData['分册名称'])
            win.Show(True)
            win.note.Bind(wx.EVT_CLOSE, self.OnCloseBook, win.note)

    def OnOpenPro(self, event):
        if not hasattr(self, 'ProData') or self.ProData == 5101:
            dlg = wx.FileDialog(self, '打开大龙山预算文件...',
                os.getcwd(), style=wx.FD_OPEN,
                wildcard=self.wildcard)
            if dlg.ShowModal() == wx.ID_OK:
                self.filename = dlg.GetPath()
                self.ReadFile()
            dlg.Destroy()
        else:
            wx.MessageBox('请先新建工程!'
                , '警告!',style=wx.OK|wx.ICON_WARNING)

    def ReadFile(self):
        if self.filename:
            try:
                f = lzma.open(self.filename, 'rb')
                data = pickle.load(f)
                # ******************************************
                # 读取数据
                self.ProData = data[0]
                self.BookList = data[1]
                self.SetTitle(self.ProData['项目名称'])
                for index, i in enumerate(self.BookList):
                    book = SqlDict().geth2edict()[i[1]['分册类型']]
                    win = FrontDataHandler(self, book, path=os.path.join(BASE_DIR, 'db'),
                    windowname=i[1]['分册名称'])
                    win.ImportData(i[4])
                    if index == len(self.BookList) - 1:
                        win.Show(True)
                    win.note.Bind(wx.EVT_CLOSE, self.OnCloseBook, win.note)
                    i.pop(4)
                # ******************************************
                f.close()
            except pickle.UnpicklingError:
                wx.MessageBox('%s 不是大龙山楠哥认证文件!'%
                self.filename, 'oops!',
                style=wx.OK|wx.ICON_EXCLAMATION)
    
    @NeedPro
    def OnChangePro(self, event):
        Dia = DiaCreatePro(self, '修改工程信息', data=self.ProData,
            path=os.path.join(BASE_DIR, 'db'))
        Data = Dia.ShowModal()
        Dia.Destroy()
        if Data != 5101:
            self.ProData = Data
            self.SetTitle(self.ProData['项目名称'])

    @NeedPro
    @NeedBook
    def OnChangeBook(self, event):
        Win = self.GetActiveChild()
        for index, i in enumerate(self.BookList):
            if i[1]['分册名称'] == Win.Name:
                names = self.GetOtherBookNames(Win.Name)
                Dia = DiaChangeBookName(self, '修改当前分册名称',
                    value=Win.Name, names=names)
                Name = Dia.ShowModal()
                Dia.Destroy()
                if Name != 5101:
                    i[1]['分册名称'] = Name
                    Win.SetName(Name)
                    Win.SetTitle(Name)

    @NeedPro
    @NeedBook
    def OnSetBook(self, event):
        OldBookList = copy.deepcopy(self.BookList)
        Dia = DiaMainChangeBook(self, '设置分成', data=OldBookList)
        NewBookList = Dia.ShowModal()
        Dia.Destroy()
        if NewBookList != 5101:
            self.BookList = copy.deepcopy(NewBookList)
            # **************************************************
            # 处理数据
            for j in NewBookList:
                if j[3] == 'CLOSE':
                    window = self.FindWindowByName(j[1]['分册名称'])
                    window.Hide()
                else:
                    window = self.FindWindowByName(j[1]['分册名称'])
                    window.Show()
            # 删除数据
            RemoveList = []
            for i in OldBookList:
                for j in NewBookList:
                    if j[1]['分册名称'] == i[1]['分册名称']:
                        RemoveList.append(i)

            for i in RemoveList:
                OldBookList.remove(i)
            
            for i in OldBookList:
                window = self.FindWindowByName(i[1]['分册名称'])
                window.Destroy()
            # **************************************************

    def OnClearHis(self, event):
        pass

    def OnImportTemp(self, event):
        pass

    @NeedPro
    @NeedBook
    def OnExportAs(self, event):
        # 导出为
        Dia = DiaPickTemp(self, '导出为', path=BASE_DIR)
        Data = Dia.ShowModal()
        Dia.Destroy()
        if Data != 5101:
            if Data[0].split('.')[-1] == 'docx':
                P = ParseDocx(Data[0], self, Data[1])
                del P
            else:
                P = ParseXls(Data[0], self, Data[1])
                del P

    @NeedPro
    @NeedBook
    def SaveFile(self):
        # 保存
        if self.filename:
            data = []
            data.append(self.ProData)
            data.append(self.BookList)
            for i in self.BookList:
                window = self.FindWindowByName(i[1]['分册名称'])
                thisdata = window.ExportData()
                i.append(thisdata)
            f = lzma.open(self.filename, 'wb')
            pickle.dump(data, f)
            f.close()

    @NeedPro
    @NeedBook
    def OnSave(self, event):
        if not self.filename:
            self.OnSaveAs(event)
        else:
            self.SaveFile()

    @NeedPro
    @NeedBook
    def OnSaveAs(self, event):
        dlg = wx.FileDialog(self, '保存为 ...',
            os.getcwd(),
            style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT,
            wildcard=self.wildcard)
        if dlg.ShowModal() == wx.ID_OK:
            filename = dlg.GetPath()
            if not os.path.splitext(filename)[1]:
                filename = filename + '.dls'
            self.filename = filename
            self.SaveFile()
        dlg.Destroy()

    def OnCloseBook(self, event):
        win = event.GetEventObject()
        name = win.Name
        for i in self.BookList:
            if i[1]['分册名称'] == name:
                i[3] = 'CLOSE'
        win.Hide()

    def OnSet(self, event):
        Dia = wx.FontDialog(self)
        Ret = Dia.ShowModal()
        print(Ret)
        print(Dia.GetFontData())
        Dia.Destroy()

    # 绑定函数 编辑
    def OnUndo(self, event):
        pass

    def OnRestore(self, event):
        pass

    def OnCopy(self, event):
        pass

    def OnPaste(self, event):
        pass

    @NeedPro
    @NeedBook
    def OnFind(self, event):
        NoteBook = self.GetActiveChild().nb
        Panel = NoteBook.GetCurrentPage()
        if Panel.sizer.IsShown(0):
            Panel.sizer.Hide(0)
        else:
            Panel.sizer.Show(0)
        Panel.sizer.Layout()
        

    def OnReplace(self, event):
        pass
    # 选项
    def OnFont(self, event):
        pass

    def OnGrid(self, event):
        pass

    def OnTheme(self, event):
        pass
    # 工具
    def OnSpy(self, event):
        pass

    def OnQuota(self, event):
        pass
    # 帮助
    def OnHelp(self, event):
        pass
    
    @NeedPro
    @NeedBook
    def OnConver2Stand(self, event):
        NoteBook = self.GetActiveChild()
        BookDict = SqlDict()
        BookDict = BookDict.geth2edict()
        if NoteBook is not None:
            dia = DiaChoiceStanderd(self)
            if dia.ShowModal() != 5101:
                Book = dia.GetStringSelection()
                Book = BookDict.get(Book)
                if Book is not None:
                    Handler = NoteBook.GetHandler()
                    Handler.OnConver2Stand(Book)
            dia.Destroy()
    
    def OnDonate(self, event):
        Dia = DiaDonate(self)
        Dia.ShowModal()
        Dia.Destroy()

    def OnAbout(self, event):
        aboutInfo = wx.adv.AboutDialogInfo()
        aboutInfo.SetName("大龙山兰戈概预算软件\n")
        aboutInfo.SetVersion('0.5Alpha')
        aboutInfo.SetDescription("""项目背景
    本人常年编制通信预算，但原有使用的概预算工具由于平台的限制无法自由地导出数据，导致平常工作中做完预算需要做很多重复的数据粘贴工作，及其耗费时间，生产效率低下。本软件使用了一套独特的语法来进行数据的查找及计算，现阶段能支持docx, xls, xlxs文档及表格文件模板数据的导出。能提高预算编制后相关工作的生产效率。
项目特色
    1、本软件SqlLite数据库内定额库为中华人民共和国工业和信息化部与2016年发布的《信息通信建设工程预算定额》（工信部通信【2016】451号），非本人编制。数据库内所有的费率皆来源于中华人民共和国工业和信息化部2016年发布的《信息通信建设工程费用定额 信息通信建设工程概预算编制规则》（工信部通信【2016】451号），非本人杜撰。
    2、本软件由大龙山兰戈（化名）一个人单独编写，版权及知识产权等所有者也为大龙山兰戈一人独享，受法律保护。
    3、未经大龙山兰戈（化名）许可，任何到位及个人不得以任何方式或理由对本软件的人和部分进行使用、复制、修改、抄录、传播或与其他产品捆绑使用、销售。
    4、凡侵犯大龙山兰戈（化名）版权等知识产权的，本人必依法追究其法律责任。""")
        aboutInfo.SetCopyright("Copyright © 2020-2021 大龙山兰戈.All rights reserved.\n")
        # aboutInfo.SetWebSite("909841193@qq.com")
        # aboutInfo.AddDeveloper("大龙山兰戈")

        wx.adv.AboutBox(aboutInfo)

    def CheckBookNameIsSame(self, string, index):
        if hasattr(self, 'BookList'):
            for thisindex, i in enumerate(self.BookList):
                if i[1]['分册名称'] == string and thisindex != index:
                    return False
        return True

    def GetOtherBookNames(self, name):
        ret = []
        if hasattr(self, 'BookList'):
            for i in self.BookList:
                ThisName = i[1]['分册名称']
                if ThisName != name:
                    ret.append(ThisName)
        
        return ret

    def BookData2Dict(self, data):
        default_mat_dis = {'光缆': 0, '电缆': 0, '塑料': 0, '木材': 0, '水泥': 0, '其他': 0, '设备': 0}
        book = SqlDict().geth2edict()[data['分册类型']]
        sc2en_dis = float(data['施工场地距离'])
        local = data['施工地点']
        specarea = data['特殊施工地区']
        mach_dis = float(data['大型机械调遣距离'])
        ton = float(data['大型机械吨位'])
        contax = float(data['施工单位增值税税率'])
        matetax = float(data['材料增值税税率'])
        servtax = float(data['服务费增值税税率'])
        mat_dis = DataTool.allfillin(default_mat_dis, float(data['材料运距']))
        discount = float(data['施工折扣']) * 100
        discountd = data['设计折扣']
        discounts = data['监理折扣']
        discountss = data['勘察折扣']
        discounta = data['审计折扣']
        discountsafe = data['安全生产费折扣']

        return (book, {'sc2en_dis':sc2en_dis, 'local':local, 
                'specarea':specarea, 'mach_dis':mach_dis,
                'ton':ton, 'contax':contax, 'matetax':matetax, 
                'servtax':servtax, 'mat_dis':mat_dis, 'discount':discount,
                'discountd':discountd, 'discounts':discounts, 
                'discountss':discountss, 'discounta':discounta,
                'discountsafe':discountsafe, })


class MainApp(wx.App):

    def OnInit(self):
        bmp = wx.Image(os.path.join(BASE_DIR, 'image/SplashScreen/SplashScreen.bmp')).ConvertToBitmap()
        wx.adv.SplashScreen(bmp, wx.adv.SPLASH_CENTRE_ON_SCREEN|wx.adv.SPLASH_TIMEOUT|wx.STAY_ON_TOP,
            5000, None, -1)
        wx.Yield()

        frame = MainFrame("*")
        frame.Show()
        frame.Center()
        frame.Maximize()
        # self.SetTopwindow(frame)
        return True



if __name__ == "__main__":
    app = MainApp()
    app.MainLoop()